﻿#include "chinese.h"
/*! ************************************************************
 * \file
 * \brief 提供字符串常用处理函数
 *
 * \authors 林胜勇
 *
 * \date
 * \verbatim
 * 变更记录：
 * 2023-11-30，林胜勇:
 *   创建文件
 * \endverbatim
 ****************************************************************/

#pragma once

#include <iomanip>
#include <set>
#include <sstream>
#include <string>
#include <vector>

#include "util.h"
#ifdef CPPC_OS_WINDOWS
#include <cctype> // 包含头文件
#endif
namespace cppc {

/// 格式化显示字节大小，选择合适的单位，KB/MB/GB
extern std::string formatByteSize(uint64 byteSize, int decimalNum = 2);

/// 根据文件大小描述字符串计算对应的数值
/// \param valueStr 文件字节大小描述，如"20MB"，"20GB"
extern uint64 parseByteSize(const std::string &byteStr);

/// 是否是空白字符
/// ' '(0x20)space(SPC) 空格符
/// '\t'(0x09)horizontal tab(TAB) 水平制表符
/// '\n'(0x0a)newline(LF) 换行符
/// '\v'(0x0b)vertical tab(VT) 垂直制表符
/// '\f'(0x0c)feed(FF) 换页符
/// '\r'(0x0d)carriage return (CR)回车符
inline bool isspace(char c) {
    return std::isspace(c);
}
/// 是否大写字符
inline bool isUpperChar(char c) {
    return c >= 'A' && c <= 'Z';
}

/// 是否小写字符
inline bool isLowerChar(char c) {
    return (c >= 'a' && c <= 'z');
}

/// 是否数字字符，如'9'
inline bool isDigitChar(char c) {
    return c >= '0' && c <= '9';
}

/// 字符串是否全部是数字字符
extern bool isDigitStr(const std::string &str);

/// 转换为小写
inline char toLowerChar(char c) {
    return (isUpperChar(c)) ? (c + 32) : c; // +32转换为小写
}

/// 转换为大写
inline char toUpperChar(char c) {
    return (isLowerChar(c)) ? (c - 32) : c; // -32转换为大写
}

/// 将字符串转为小写
extern std::string &toLowerStr(std::string &str);

/// 将字符串转为小写
extern std::string toLowerStr(std::string &&str);

/// 将字符串转为大写
extern std::string &toUpperStr(std::string &s);

/// 将字符串转为大写
extern std::string toUpperStr(std::string &&s);

/// 将数值[0-15]转为对应十六进制字符形式
/// example:10 -> 'A',15 -> 'F'
extern char toHexChar(uint8 x);

/// 将十六进制字符[0-9|a-f|A-F]转为数值[0-15]
/// example:'A' -> 10,'F' -> 15
extern uint8 toUInt(char hex);

/// 将字符串（二进制数据）转为十六进制字符串
/// \param delim各字节转为十六进制后的分隔符，默认是空格
/// \return  hex std::string :"AF B0 80 7D"
extern std::string toHexString(const char *in, uint length, char delim = '\x20');

/// 去除前后的空格等不可见字符
extern void trim(std::string &s, const std::string chars = "\a\b\t\r\n\v\f\x20");

/// 替换子字符串
extern void replace(std::string &str, const std::string &oldStr, const std::string &newStr, std::string::size_type startPos = 0);

/// 字符串拼接
extern std::string join(std::set<std::string> &strSet, const std::string &pattern);

/// 字符串分割
extern std::vector<std::string> split(const std::string &str, const std::string &delim);

/// 分隔参数，提取各部分信息，如提取-v=12的三个名称和值
/// \param[in] tokenStr
/// 待分解字符串，如-v=12，或者-h这种形式。如果遇到-v==2，会自动忽略多余的=。
/// \param[in] delimiters 分隔符，一般为＝号
/// \param[out] tokens 分解后逐个保存，如-v=12会分解成-v,=,12三部分
/// \return token信息被分解成几个部分
extern std::vector<std::string> splitToken(const std::string &tokenStr, const std::string &delim);

/// 字符串是否以substr开头
extern bool startWith(const std::string &str, const std::string &substr);

/// 字符串是否以substr结尾
extern bool endWith(const std::string &str, const std::string &substr);

/// 如果字符串过长，则进行省略处理
extern std::string limitStringSize(const std::string &str, uint maxSize);

/// 转换hex string为单独的字符集合.
/// \param strSrc: hex std::string:"AF B0 80 7D"
extern std::vector<char> hexStringToChars(const std::string &strSrc, const std::string &delim = "");

/// 将字符集转为字符串
extern std::string charsToString(const std::vector<char> &chars);

/// 将16进制字符串序列转成uint
extern uint hexStringToUInt(const std::string &strSrc, const std::string &delim = "");

/// 将16进制字符串序列转成int
extern int hexStringToInt(const std::string &strSrc, const std::string &delim = "");

/// 将uint转换为16进制字符串序列
/// \param value 待转换数值
/// \param byteLength 指定uint的有效字符数，2时转换为1122，3时转换为112233
/// \param prefix 是否添加前缀0X
extern std::string toHexString(uint value, int byteLength = 4, bool prefix = false);

/// 将int转换为16进制字符串序列
/// \param value 待转换数值
/// \param byteLength 指定uint的有效字符数，2时转换为1122，3时转换为112233
/// \param prefix 是否添加前缀0X
extern std::string toHexString(int value, int byteLength = 4, bool prefix = false);

/// 将uint转换为16进制字符串序列
/// 根据具体的值的范围，自动计算其有效字符数
extern std::string toMinHexString(uint value, bool prefix = false);

/// 将int转换为16进制字符串序列
/// 根据具体的值的范围，自动计算其有效字符数
extern std::string toMinHexString(int value, bool prefix = false);

#if _WIN32 || WIN32
/// Unicode字符转Ascii字符
extern std::string unicodeToAscii(const std::wstring &str);

/// Ascii字符转Unicode
extern std::wstring asciiToUnicode(const std::string &str);

extern std::wstring stringToWstring(const std::string &str);

extern std::string wstringToString(const std::wstring &wstr);

/// Unicode转utf8
extern std::string unicodeToUtf8(const std::wstring &wstrUnicode);

/// utf8转Unicode
extern std::wstring utf8ToUnicode(const std::string &str);
#endif

/// 浮点数转为字符串
/// \param value 浮点值
/// \param decimalNum 小数位个数
/// \param round 是否四舍五入
/// \param removeLastZero 是否清理小数点后末尾的0和小数位
template <typename T>
std::string toStringWithPrecision(T value, uint decimalNum, bool round = false, bool removeLastZero = false) {
    T t_value = setPrecision(value, decimalNum, round);

    std::ostringstream t_out;
    t_out << std::fixed << std::setprecision(decimalNum) << t_value;

    // 将字符串流中的内容转换为字符串
    std::string result = t_out.str();

    if (removeLastZero && decimalNum > 0) {
        // 去掉小数点后末尾的零
        size_t found = result.find_last_not_of('0');

        if (found != std::string::npos) {
            result.erase(found + 1);
        }

        // 如果末尾是小数点，也去掉
        if (result.back() == '.') {
            result.pop_back();
        }
    }

    return result;
}

/// 生成一个随机字符串
/// @param size 字符串长度
/// @param printable 是否生成为可打印字符或数字
/// @return 生成的字符串
extern std::string makeRandStr(int size, bool printable);

template <typename T>
inline T strToValue(const std::string &str, T defaultValue) {
    T t;
    return (std::istringstream(str) >> t) ? t : defaultValue;
}

template <typename T>
inline T strToValue(const std::string &str) {
    T t;
    std::istringstream(str) >> t;
    return t;
}

template <>
inline bool strToValue(const std::string &str) {
    return (str.size() && (str != "0") && (str != "false") && (str != "FALSE"));
}

template <>
inline char strToValue(const std::string &str) {
    return str.size() == 1 ? (char)(str[0]) : (char)(strToValue<int>(str));
}

template <>
inline signed char strToValue(const std::string &str) {
    return str.size() == 1 ? (signed char)(str[0]) : (signed char)(strToValue<int>(str));
}

template <>
inline unsigned char strToValue(const std::string &str) {
    return str.size() == 1 ? (unsigned char)(str[0]) : (unsigned char)(strToValue<int>(str));
}

template <>
inline const char *strToValue(const std::string &str) {
    return str.c_str();
}

template <>
inline std::string strToValue(const std::string &str) {
    return str;
}

/// 两个字符串是否相同
inline bool isSame(const std::string &a, const std::string b) {
    return a.compare(b) == 0;
}

template <typename T = char>
inline std::string toString(const std::vector<T> &vectorObj) {
    const char *str = &(*vectorObj.begin());
    return std::move(std::string(str, vectorObj.size()));
}

template <typename T = char>
inline std::vector<T> toVector(const std::string &str) {
    std::vector<T> vectorObj;
    vectorObj.assign(str.begin(), str.end());

    return std::move(vectorObj);
}

} // namespace cppc
